package com.jeomo.mem.starter.service.impl;

import com.jeomo.base.starter.service.impl.BaseServiceImpl;
import com.jeomo.common.core.constant.SearchParam;
import com.jeomo.common.core.constant.Sort;
import com.jeomo.common.core.constant.SystemConst;
import com.jeomo.common.core.dto.PageQueryDto;
import com.jeomo.common.core.dto.PageResponseDto;
import com.jeomo.common.core.exception.BusinessException;
import com.jeomo.common.core.result.CommonResult;
import com.jeomo.common.core.util.BeanCopyUtil;
import com.jeomo.common.core.util.StringUtils;
import com.jeomo.masterdata.starter.entity.Level;
import com.jeomo.masterdata.starter.entity.Region;
import com.jeomo.masterdata.starter.mapper.LevelMapper;
import com.jeomo.masterdata.starter.mapper.RegionMapper;
import com.jeomo.masterdata.starter.service.ILevelService;
import com.jeomo.mem.starter.dto.MemberInfoDto;
import com.jeomo.mem.starter.entity.*;
import com.jeomo.mem.starter.enums.MemLevelSrcTypeEnum;
import com.jeomo.mem.starter.enums.MemberCardStatusEnum;
import com.jeomo.mem.starter.exception.MemberCardException;
import com.jeomo.mem.starter.mapper.*;
import com.jeomo.mem.starter.service.IMemberCardService;
import com.jeomo.shiro.dto.LoginInfo;
import com.jeomo.shiro.util.LoginSessionUtil;
import com.jeomo.shiro.util.OrgUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 会员卡服务
 * @author:Jackpot
 * @create 2020-10-22 20:20
 * @description:
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class MemberCardServiceImpl extends BaseServiceImpl<MemberCardMapper, MemberCard>
        implements IMemberCardService {

    private final String CARD_NO = "card_no";
    private final String MEMBER_NAME = "name";
    private final String PHONE = "phone";
    private final String MEM_LEVEL = "mem_level";
    private final String SEX = "sex";
    private final String MEM_STATUS = "mem_status";

    private final String BIRTHDAY = "birthday";
    private final String BIRTHDAY_FROM = "birthday_from";
    private final String BIRTHDAY_TO = "birthday_to";
    private final String OPEN_TIME = "open_time";
    private final String OPEN_TIME_FROM = "open_time_from";
    private final String OPEN_TIME_TO = "open_time_to";

    @Resource
    private MemberMapper memberMapper;
    @Resource
    private MemberCardMapper memberCardMapper;
    @Resource
    private RegionMapper regionMapper;
    @Resource
    private ILevelService levelService;
    @Resource
    private LevelMapper levelMapper;
    @Resource
    private MemberPointsExecMapper memberPointsExecMapper;
    @Resource
    private MemPointsDetailMapper memPointsDetailMapper;
    @Resource
    private MemConsumeDetailMapper memConsumeDetailMapper;
    @Resource
    private MemberLevelExeService memberLevelExeService;

    @Override
    public int registerMemberCard(MemberInfoDto memberInfoDto) {

        LoginInfo loginInfo = LoginSessionUtil.getCurrentLoginInfo();
        memberInfoDto.setTopOrgCode(loginInfo.getTopOrgCode());
        memberInfoDto.setOrg(loginInfo.getOrgCode());
        memberInfoDto.setPoints(0);
        memberInfoDto.setTotalWinPoints(0);
        memberInfoDto.setTotalConsumeAmount(0D);
        memberInfoDto.setTotalConsumeNumber(0);
        memberInfoDto.setMemStatus(MemberCardStatusEnum.NORMAL.getCode());
        LocalDateTime now = LocalDateTime.now();
        //注册会员信息
        Member member = BeanCopyUtil.copyProperties(memberInfoDto, Member.class);
        String memberPhone = member.getMemberPhone();
        if (!verifyPhone(member.getTopOrgCode(),memberPhone)) {
            throw new BusinessException("注册失败: 手机号重复注册,请更换手机号!");
        }
        member.setRegTime(now);
        int insert = memberMapper.insert(member);
        if (insert!=1) {
            throw new BusinessException("会员信息注册失败!");
        }
        String memberNo = member.getCode();
        //注册会员卡信息
        MemberCard memberCard = BeanCopyUtil.copyProperties(memberInfoDto, MemberCard.class);
        memberCard.setMemberNo(memberNo);
        memberCard.setPhone(memberPhone);
        memberCard.setOpenTime(now);
        int insert1 = memberCardMapper.insert(memberCard);
        if (insert1!=1) {
            throw new BusinessException("会员卡注册失败!");
        }
        //记录会员等级执行信息
        String cardNo = memberCard.getCardNo();
        String levelCode = memberCard.getMemLevel();
        Level level = levelMapper.selectById(levelCode);
        Integer effectiveDay = level.getEffectiveDay();
        int srcType = MemLevelSrcTypeEnum.REGISTER.getCode();
        memberLevelExeService.initLevelExe(cardNo,levelCode,now,now.plusDays(effectiveDay).toLocalDate(),srcType);
        return insert+insert1;
    }

    /**
     * 校验是否重复注册
     * @param topOrg
     * @param phone
     * @return
     */
    public boolean verifyPhone(String topOrg,String phone){
        Member member = memberMapper.queryMemberByPhone(topOrg, phone);
        return member==null?true:false;
    }

    @Override
    public Member queryMemberByPhone(String topOrg, String phone) {
        return memberMapper.queryMemberByPhone(topOrg,phone);
    }

    @Override
    public MemberCard queryMemCardByPhone(String org, String phone) {
        return memberCardMapper.queryMemCardByPhone(org,phone);
    }

    @Override
    public List<MemberCard> queryAllMemCards() {
        return memberCardMapper.queryAllMemCards();
    }

    @Override
    public MemberCard queryMemCardByPhoneOrNo(String org, String number) {
        MemberCard memberCard = memberCardMapper.queryMemCardByPhoneOrNo(org,number);
        return patchParam(memberCard);
    }

    @Override
    public MemberCard queryMemCardByNo(String cardNo) {
        MemberCard memberCard = memberCardMapper.queryMemCardByNo(cardNo);
        return patchParam(memberCard);
    }

    public MemberCard patchParam(MemberCard memberCard){
        if (memberCard ==null) return null;
        Integer city = memberCard.getCity();
        String cityName=null;
        if (city!=null){
            Region region = regionMapper.queryRegionById(city);
            if (region!=null) cityName = region.getName();
        }
        memberCard.setCityName(cityName);
        Map<String, String> levelMap = levelService.queryCache();
        memberCard.setMemLevelName(levelMap.get(memberCard.getMemLevel()));
        return memberCard;
    }

    @Override
    public PageResponseDto pageSearch(PageQueryDto dto) {
        String currOrg = OrgUtil.getCurrOrg();
        //1. 处理查询参数
        Map<String, Object> searchParams = dto.getSearchParams();
        Map<String, Object> params = new HashMap<>();
        if(searchParams!=null){
            params.put(SearchParam.SEARCH_EQ+ "member_card."+SystemConst.ORG,currOrg);//组织隔离
            params.put(SearchParam.SEARCH_EQ+CARD_NO,searchParams.get(CARD_NO));
            params.put(SearchParam.SEARCH_LIKE+MEMBER_NAME,searchParams.get(MEMBER_NAME));//全模糊
            params.put(SearchParam.SEARCH_EQ+PHONE,searchParams.get(PHONE));
            params.put(SearchParam.SEARCH_EQ+MEM_LEVEL,searchParams.get(MEM_LEVEL));
            params.put(SearchParam.SEARCH_GE+BIRTHDAY,searchParams.get(BIRTHDAY_FROM));
            params.put(SearchParam.SEARCH_LE+BIRTHDAY,searchParams.get(BIRTHDAY_TO));
            params.put(SearchParam.SEARCH_EQ+SEX,searchParams.get(SEX));
            params.put(SearchParam.SEARCH_EQ+MEM_STATUS,searchParams.get(MEM_STATUS));
            params.put(SearchParam.SEARCH_GE+OPEN_TIME,searchParams.get(OPEN_TIME_FROM));
            params.put(SearchParam.SEARCH_LE+OPEN_TIME,searchParams.get(OPEN_TIME_TO));
        }
        dto.setSearchParams(params);
        Map<String, String> sort = new HashMap<>(8);
        sort.put(OPEN_TIME, Sort.DESC);
        dto.setSorts(sort);

        PageResponseDto response = super.pageSearch(dto);
        //2. 处理返回结果
        List<?> items = response.getItems();
        for (Object item : items) {
            patchParam((MemberCard)item);
        }
        return response;
    }

    @Override
    public int updateCardStatus(String cardNo, String status) {
        MemberCard memberCard = new MemberCard();
        memberCard.setCardNo(cardNo);
        memberCard.setMemStatus(status);
        return memberCardMapper.updateById(memberCard);
    }

    @Override
    public int updateMemberInfo(Member member) {
        return memberMapper.updateById(member);
    }

    @Override
    public void updateMemberPoints(MemberPointsUpdate memberPointsUpdate) {
        Objects.requireNonNull(memberPointsUpdate,"memberPointsUpdate");
        Integer pointsChange = memberPointsUpdate.getPointsChange();
        if (pointsChange==null ||pointsChange==0) return;
        //更新积分执行单
        updateMemberPointsExec(memberPointsUpdate);
        //新增积分明细
        addMemberPointsDetail(memberPointsUpdate);
        //更新会员卡积分
        updateMemberCardPoints(memberPointsUpdate);
    }

    /**
     * 新增/更新积分执行单, 失败自动抛出异常,事务回滚;
     * @param memberPointsUpdate
     */
    public void updateMemberPointsExec(MemberPointsUpdate memberPointsUpdate){
        String cardNo = memberPointsUpdate.getCardNo();
        int pointsChange = memberPointsUpdate.getPointsChange();
        LocalDateTime handleTime = memberPointsUpdate.getHandleTime();
        LocalDate expiredTime = memberPointsUpdate.getExpiredTime();
        if (pointsChange >0){
            Objects.requireNonNull(expiredTime,"expiredTime");
            MemberPointsExec memberPointsExec = new MemberPointsExec();
            memberPointsExec.setCardNo(cardNo);
            memberPointsExec.setPoints(pointsChange);
            memberPointsExec.setAcquireTime(handleTime);
            memberPointsExec.setExpiredTime(expiredTime);
            memberPointsExecMapper.insert(memberPointsExec);
        }else if (pointsChange <0){
            List<MemberPointsExec> memberPointsExecs = memberPointsExecMapper.queryPointsExe(cardNo, LocalDateTime.now());
            for (MemberPointsExec pointsExec : memberPointsExecs) {
                Integer points = pointsExec.getPoints();
                pointsChange += points;
                pointsExec.setPoints(pointsChange >=0 ? pointsChange:0);
                int i = memberPointsExecMapper.updateById(pointsExec);
                if (i==0) throw new MemberCardException("积分执行单更新失败!");
                if (pointsChange >=0) break;
            }
        }
    }

    /**
     * 新增积分明细
     * @param memberPointsUpdate
     */
    public void addMemberPointsDetail(MemberPointsUpdate memberPointsUpdate){
        MemberPointsDetail detail = BeanCopyUtil.copyProperties(memberPointsUpdate, MemberPointsDetail.class);
        verifyIsSafe(detail);
        int insert = memPointsDetailMapper.insert(detail);
        if (insert==0) throw new MemberCardException("积分明细新增失败!");
    }

    /**
     * 数据完整性校验
     * @param memberPointsDetail
     * @return
     */
    private boolean verifyIsSafe(MemberPointsDetail memberPointsDetail){
        String cardNo = memberPointsDetail.getCardNo();
        String memberNo = memberPointsDetail.getMemberNo();
        String srcCode = memberPointsDetail.getSrcCode();
        String srcTypeCode = memberPointsDetail.getSrcTypeCode();
        LocalDateTime handleTime = memberPointsDetail.getHandleTime();
        Integer pointsOld = memberPointsDetail.getPointsOld();
        Integer pointsChange = memberPointsDetail.getPointsChange();
        if (StringUtils.isEmpty(cardNo) || StringUtils.isEmpty(memberNo) ||StringUtils.isEmpty(srcTypeCode) ||
                StringUtils.isEmpty(srcCode)  || handleTime ==null || pointsOld ==null  || pointsChange ==null  ){
            throw new BusinessException("积分明细的部分数据字段值为空,请检查!");
        }
        return true;
    }

    /**
     * 更新会员卡积分
     * @param memberPointsUpdate
     */
    public void updateMemberCardPoints(MemberPointsUpdate memberPointsUpdate){

        String cardNo = memberPointsUpdate.getCardNo();
        Long cardVersion = memberPointsUpdate.getCardVersion();
        int pointsChange = memberPointsUpdate.getPointsChange();
        int accPoints = pointsChange>0? pointsChange:0;
        int i = memberCardMapper.updateCardPoints(cardNo, cardVersion, pointsChange, accPoints);
        if (i==0) throw new MemberCardException("会员卡积分更新失败!");
    }

    @Override
    public int getCurrPoints(String cardNo) {
        Integer points = memberPointsExecMapper.getPoints(cardNo, LocalDate.now());
        return points!=null?points:0;
    }

    @Override
    public int getPoints(String cardNo,LocalDate date) {
        Integer points = memberPointsExecMapper.getPoints(cardNo, date);
        return points!=null?points:0;
    }

    @Override
    public void recordConsumeDetail(MemberConsumeDetail memberConsumeDetail) {
        //记录消费流水
        int insert = memConsumeDetailMapper.insert(memberConsumeDetail);
        if (insert==0) throw new BusinessException("记录消费流水出现异常!");
        //修改会员卡信息
        String cardNo = memberConsumeDetail.getCardNo();
        Long cardVersion = memberConsumeDetail.getCardVersion();
        Double payAmount = memberConsumeDetail.getPayAmount();
        int i = memberCardMapper.updateCardAmount(cardNo, cardVersion, payAmount);
        if (i==0) throw new BusinessException("修改会员卡金额信息出现异常!");
    }
}
